package dht.data;

import java.util.Random;
import java.util.TreeMap;

import dht.simulation.GlobalVariables;

public class AccessGenerator {

	public static final double interval = 0.00004;
	protected Random ran;
	protected double timeOffset;

	public AccessGenerator() {
		ran = new Random(GlobalVariables.seed);
		timeOffset = 0;
	}

	/**
	 * 
	 * @param lambdaR
	 *            Average read access in 1 second
	 * @param lambdaW
	 *            Average write access in 1 second
	 */
	public TreeMap<Double, AccessType> generate(int lambdaR, int lambdaW,
			double totalTime) {
		TreeMap<Double, AccessType> res = new TreeMap<Double, AccessType>();
		int period = (int) ((totalTime + GlobalVariables.eps) / interval);
		// Read
		for (int i = 0; i < period; ++i) {
			double dice = ran.nextDouble();
			int k = 0;
			double poisson = Math.pow(Math.E, -lambdaR * interval);
			double sum = poisson;
			while (sum <= dice) {
				k++;
				poisson *= lambdaR * interval / k;
				sum += poisson;
			}
			for (int j = 0; j < k; ++j) {
				double time = ran.nextDouble() * interval;
				while (res.containsKey(timeOffset + i * interval + time)) {
					time += GlobalVariables.eps;
				}
				res.put(timeOffset + i * interval + time, AccessType.READ);
			}
		}

		// Write
		for (int i = 0; i < period; ++i) {
			double dice = ran.nextDouble();
			int k = 0;
			double poisson = Math.pow(Math.E, -lambdaW * interval);
			double sum = poisson;
			while (sum <= dice) {
				k++;
				poisson *= lambdaW * interval / k;
				sum += poisson;
			}
			for (int j = 0; j < k; ++j) {
				double time = ran.nextDouble() * interval;
				while (res.containsKey(timeOffset + i * interval + time)) {
					time += GlobalVariables.eps;
				}
				res.put(timeOffset + i * interval + time, AccessType.WRITE);
			}
		}
		timeOffset += totalTime;
		return res;
	}

	public static void main(String[] args) {
		AccessGenerator gen = new AccessGenerator();
		TreeMap<Double, AccessType> access = gen.generate(5, 2, 1);
		// System.out.println(access.size());
		for (Double key : access.keySet()) {
			System.out.println(key + " " + access.get(key));
		}
	}

}
